package com.smartwrite.service;

import com.smartwrite.entity.TaskInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import com.smartwrite.enums.TaskStatus;

/**
 * 报告执行服务
 * 负责执行报告生成任务的具体逻辑
 */
@Service
public class ReportExecutorService {

    @Autowired
    private TaskStorageService taskStorageService;
    
    @Autowired
    private TaskProgressMonitorService taskProgressMonitorService;

    // Python引擎路径
    @Value("${smartwrite.recursive.path:${user.home}/smartwrite/WriteHERE/recursive}")
    private String recursivePath;
    
    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 执行报告生成任务
     * @param taskInfo 任务信息
     */
    public void executeReportGeneration(TaskInfo taskInfo) {
        String taskId = taskInfo.getTaskId();
        try {
            // 更新状态为运行中
            taskInfo.setStatus(TaskStatus.RUNNING);
            taskStorageService.updateTask(taskInfo);
            
            // 创建输入文件
            createInputFile(taskInfo);
            
            // 创建环境变量文件
            createEnvironmentFile(taskInfo);
            
            // 创建执行脚本
            String scriptPath = createExecutionScript(taskInfo);
            
            // 启动进度监控
            taskProgressMonitorService.startMonitoring(taskId, 
                Paths.get(taskInfo.getTaskDir(), "records").toString());
            
            // 执行脚本
            executeScript(taskInfo, scriptPath);
            
        } catch (Exception e) {
            // 更新任务错误状态
            taskStorageService.updateTaskError(taskId, "执行报告生成失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * 创建输入文件
     */
    private void createInputFile(TaskInfo taskInfo) throws IOException {
        Path inputFile = Paths.get(taskInfo.getTaskDir(), "input.jsonl");
        
        Map<String, Object> inputData = new HashMap<>();
        inputData.put("topic", "");
        inputData.put("intent", "");
        inputData.put("domain", "");
        inputData.put("id", taskInfo.getTaskId());
        inputData.put("prompt", taskInfo.getPrompt());
        
        String jsonContent = objectMapper.writeValueAsString(inputData) + "\n";
        Files.writeString(inputFile, jsonContent);
    }
    
    /**
     * 创建环境变量文件
     */
    private void createEnvironmentFile(TaskInfo taskInfo) throws IOException {
        Path envFile = Paths.get(taskInfo.getTaskDir(), "api_key.env");
        
        StringBuilder envContent = new StringBuilder();
        Map<String, String> apiKeys = taskInfo.getApiKeys();
        
        if (apiKeys != null) {
            if (apiKeys.containsKey("openai") && apiKeys.get("openai") != null) {
                envContent.append("OPENAI=").append(apiKeys.get("openai")).append("\n");
            }
            if (apiKeys.containsKey("claude") && apiKeys.get("claude") != null) {
                envContent.append("CLAUDE=").append(apiKeys.get("claude")).append("\n");
            }
            if (apiKeys.containsKey("gemini") && apiKeys.get("gemini") != null) {
                envContent.append("GEMINI=").append(apiKeys.get("gemini")).append("\n");
            }
            if (apiKeys.containsKey("serpapi") && apiKeys.get("serpapi") != null) {
                envContent.append("SERPAPI=").append(apiKeys.get("serpapi")).append("\n");
            }
        }
        
        Files.writeString(envFile, envContent.toString());
    }
    
    /**
     * 创建执行脚本
     */
    private String createExecutionScript(TaskInfo taskInfo) throws IOException {
        Path scriptFile = Paths.get(taskInfo.getTaskDir(), "run.sh");
        
        String inputFile = Paths.get(taskInfo.getTaskDir(), "input.jsonl").toString();
        String outputFile = Paths.get(taskInfo.getTaskDir(), "result.jsonl").toString();
        String doneFile = Paths.get(taskInfo.getTaskDir(), "done.txt").toString();
        String envFile = Paths.get(taskInfo.getTaskDir(), "api_key.env").toString();
        String nodesFile = Paths.get(taskInfo.getTaskDir(), "records", "nodes.json").toString();
        
        String engineBackend = (taskInfo.getEnableSearch() != null && taskInfo.getEnableSearch()) 
            ? taskInfo.getSearchEngine() : "none";
        
        StringBuilder scriptContent = new StringBuilder();
        scriptContent.append("#!/bin/bash\n");
        scriptContent.append("cd ").append(recursivePath).append("\n");
        scriptContent.append("source ").append(envFile).append("\n");
        scriptContent.append("export TASK_ENV_FILE=").append(envFile).append("\n");
        scriptContent.append("python engine.py ");
        scriptContent.append("--filename ").append(inputFile).append(" ");
        scriptContent.append("--output-filename ").append(outputFile).append(" ");
        scriptContent.append("--done-flag-file ").append(doneFile).append(" ");
        scriptContent.append("--model ").append(taskInfo.getModel()).append(" ");
        scriptContent.append("--engine-backend ").append(engineBackend).append(" ");
        scriptContent.append("--mode report ");
        scriptContent.append("--nodes-json-file ").append(nodesFile).append("\n");
        
        Files.writeString(scriptFile, scriptContent.toString());
        
        // 设置执行权限
        scriptFile.toFile().setExecutable(true);
        
        return scriptFile.toString();
    }
    
    /**
     * 执行脚本
     */
    private void executeScript(TaskInfo taskInfo, String scriptPath) {
        try {
            ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash", scriptPath);
            processBuilder.directory(new File(recursivePath));
            
            Process process = processBuilder.start();
            taskInfo.setProcess(process);
            
            // 异步处理进程输出
            CompletableFuture.runAsync(() -> handleProcessOutput(process, taskInfo.getTaskId()));
            
            // 等待进程完成
            int exitCode = process.waitFor();
            
            if (exitCode == 0) {
                // 检查结果文件
                Path resultFile = Paths.get(taskInfo.getTaskDir(), "result.jsonl");
                if (Files.exists(resultFile)) {
                    String resultContent = Files.readString(resultFile);
                    if (!resultContent.trim().isEmpty()) {
                        try {
                            Map<String, Object> resultMap = objectMapper.readValue(resultContent, Map.class);
                            String result = (String) resultMap.get("result");
                            taskStorageService.updateTaskResult(taskInfo.getTaskId(), result);
                        } catch (Exception e) {
                            taskStorageService.updateTaskResult(taskInfo.getTaskId(), resultContent);
                        }
                    } else {
                        taskStorageService.updateTaskError(taskInfo.getTaskId(), "生成的结果文件为空");
                    }
                } else {
                    taskStorageService.updateTaskError(taskInfo.getTaskId(), "未生成结果文件");
                }
            } else {
                taskStorageService.updateTaskError(taskInfo.getTaskId(), "脚本执行失败，退出码: " + exitCode);
            }
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            taskStorageService.updateTaskError(taskInfo.getTaskId(), "任务被中断");
        } catch (Exception e) {
            taskStorageService.updateTaskError(taskInfo.getTaskId(), "执行脚本时发生错误: " + e.getMessage());
        } finally {
            // 停止进度监控
            taskProgressMonitorService.stopMonitoring(taskInfo.getTaskId());
        }
    }
    
    /**
     * 处理进程输出
     */
    private void handleProcessOutput(Process process, String taskId) {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
             BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
            
            // 处理标准输出
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println("[" + taskId + "] " + line);
            }
            
            // 处理错误输出
            StringBuilder errorOutput = new StringBuilder();
            while ((line = errorReader.readLine()) != null) {
                System.err.println("[" + taskId + "] ERROR: " + line);
                errorOutput.append(line).append("\n");
            }
            
            // 如果有错误输出，记录到任务中
            if (errorOutput.length() > 0) {
                TaskInfo taskInfo = taskStorageService.getTask(taskId);
                if (taskInfo != null && !taskInfo.isCompleted()) {
                    taskStorageService.updateTaskError(taskId, "执行过程中出现错误: " + errorOutput.toString());
                }
            }
            
        } catch (IOException e) {
            System.err.println("处理进程输出时发生错误: " + e.getMessage());
        }
    }
    
    /**
     * 停止任务执行
     */
    public boolean stopTaskExecution(String taskId) {
        TaskInfo taskInfo = taskStorageService.getTask(taskId);
        if (taskInfo != null && taskInfo.getProcess() != null) {
            Process process = taskInfo.getProcess();
            if (process.isAlive()) {
                // 尝试优雅关闭
                process.destroy();
                
                try {
                    // 等待3秒
                    if (!process.waitFor(3, TimeUnit.SECONDS)) {
                        // 强制关闭
                        process.destroyForcibly();
                        process.waitFor(2, TimeUnit.SECONDS);
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    process.destroyForcibly();
                }
                
                // 停止进度监控
                taskProgressMonitorService.stopMonitoring(taskId);
                
                // 更新任务状态
                taskStorageService.updateTaskStatus(taskId, "stopped");
                return true;
            }
        }
        return false;
    }
}